Skip to main content

aviutl2\generic\binding/
edit_handle.rs

1use std::num::NonZeroIsize;
2use std::sync::Mutex;
3
4use crate::common::{ChildKillablePointer, KillablePointer};
5use crate::filter::RgbaPixel;
6use crate::generic::{EditSection, ReadSection};
7
8/// 編集ハンドル。
9///
10/// # Panics
11///
12/// [`crate::generic::GenericPlugin::register`]が終了するまでは、以下のメソッド以外は呼び出せません。
13/// - [`Self::get_host_app_window`]
14/// - [`Self::get_host_app_window_raw`]
15/// - [`Self::is_ready`]
16///
17#[derive(Debug)]
18pub struct EditHandle {
19    pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE,
20    pub(crate) is_ready: std::sync::Arc<std::sync::atomic::AtomicBool>,
21}
22
23unsafe impl Send for EditHandle {}
24unsafe impl Sync for EditHandle {}
25
26/// [`EditHandle`] 関連のエラー。
27#[derive(thiserror::Error, Debug)]
28pub enum EditHandleError {
29    #[error("api call failed")]
30    ApiCallFailed,
31    #[error("effect does not exist")]
32    EffectNotFound,
33    #[error("input utf-16 string contains null byte")]
34    InputCwstrContainsNull(#[from] crate::common::NullByteError),
35    #[error("unknown edit state: {0}")]
36    UnknownEditState(i32),
37    #[error("value is out of range")]
38    ValueOutOfRange,
39}
40
41/// シーンの映像レンダリング結果。
42#[derive(Debug, Clone, Copy)]
43pub struct RenderingSceneVideo<'a> {
44    /// レンダリング対象のフレーム。
45    pub frame: u32,
46    /// レンダリングした画像の幅。
47    pub width: u32,
48    /// レンダリングした画像の高さ。
49    pub height: u32,
50    /// 画像データの横1ラインのバイト数。
51    pub pitch: u32,
52    /// レンダリングした画像データ。
53    ///
54    /// データはコールバック中のみ有効です。
55    pub buffer: &'a [u8],
56}
57
58impl RenderingSceneVideo<'_> {
59    /// レンダリングした画像データを RGBA ピクセル列として取得する。
60    ///
61    /// `pitch == width * size_of::<RgbaPixel>()` の場合のみ `Some` を返します。
62    pub fn as_rgba_pixels(&self) -> Option<&[RgbaPixel]> {
63        let expected_pitch = self.width as usize * std::mem::size_of::<RgbaPixel>();
64        if self.pitch as usize != expected_pitch {
65            return None;
66        }
67        Some(unsafe {
68            std::slice::from_raw_parts(
69                self.buffer.as_ptr() as *const RgbaPixel,
70                self.width as usize * self.height as usize,
71            )
72        })
73    }
74}
75
76/// シーンの音声レンダリング結果。
77#[derive(Debug, Clone, Copy)]
78pub struct RenderingSceneAudio<'a> {
79    /// レンダリング対象のフレーム。
80    pub frame: u32,
81    /// レンダリングした音声データ(左チャンネル)。
82    ///
83    /// データはコールバック中のみ有効です。
84    pub buffer0: &'a [f32],
85    /// レンダリングした音声データ(右チャンネル)。
86    ///
87    /// データはコールバック中のみ有効です。
88    pub buffer1: &'a [f32],
89}
90
91impl EditHandle {
92    pub(crate) unsafe fn new(
93        internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE,
94        is_ready: std::sync::Arc<std::sync::atomic::AtomicBool>,
95    ) -> Self {
96        Self { internal, is_ready }
97    }
98
99    /// 編集ハンドルの初期化が完了しているかどうかを確認します。
100    pub fn is_ready(&self) -> bool {
101        self.is_ready.load(std::sync::atomic::Ordering::Acquire)
102    }
103
104    /// プロジェクトデータの編集を開始する。
105    ///
106    /// # Note
107    ///
108    /// 内部では call_edit_section_param を使用しています。
109    pub fn call_edit_section<'a, T, F>(&self, callback: F) -> Result<T, EditHandleError>
110    where
111        T: Send + 'static,
112        F: FnOnce(&mut EditSection) -> T + Send + 'a,
113    {
114        assert!(
115            self.is_ready(),
116            "call_edit_section cannot be called before register_plugin is done"
117        );
118
119        type CallbackParam<'a, F, T> = (ChildKillablePointer<Option<F>>, &'a mut Option<T>);
120
121        let closure = Some(callback);
122        let param = KillablePointer::new(closure);
123        let child_param = param.create_child();
124
125        extern "C" fn trampoline<F, T>(
126            param: *mut std::ffi::c_void,
127            edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
128        ) where
129            T: Send + 'static,
130            F: FnOnce(&mut EditSection) -> T,
131        {
132            unsafe {
133                let (child_param, result_ptr) = &mut *(param as *mut CallbackParam<F, T>);
134                let callback = child_param.as_mut().take().expect("Callback already taken");
135                let mut edit_section = EditSection::from_raw(edit_section);
136                let res = callback(&mut edit_section);
137                result_ptr.replace(res);
138            }
139        }
140
141        let trampoline_static = trampoline::<F, T>
142            as extern "C" fn(*mut std::ffi::c_void, *mut aviutl2_sys::plugin2::EDIT_SECTION);
143
144        let mut result = None;
145        let param = Box::<CallbackParam<F, T>>::new((child_param, &mut result));
146        let param_ptr = Box::into_raw(param);
147
148        let success = unsafe {
149            ((*self.internal).call_edit_section_param)(
150                param_ptr as *mut std::ffi::c_void,
151                trampoline_static,
152            )
153        };
154
155        drop(unsafe { Box::from_raw(param_ptr) });
156
157        if success {
158            Ok(result.expect("Callback did not set result"))
159        } else {
160            Err(EditHandleError::ApiCallFailed)
161        }
162    }
163
164    /// プロジェクトデータの参照を開始する。
165    ///
166    /// # Note
167    ///
168    /// 内部では call_read_section_param を使用しています。
169    pub fn call_read_section<'a, T, F>(&self, callback: F) -> Result<T, EditHandleError>
170    where
171        T: Send + 'static,
172        F: FnOnce(&ReadSection) -> T + Send + 'a,
173    {
174        assert!(
175            self.is_ready(),
176            "call_read_section cannot be called before register_plugin is done"
177        );
178
179        type CallbackParam<'a, F, T> = (ChildKillablePointer<Option<F>>, &'a mut Option<T>);
180
181        let closure = Some(callback);
182        let param = KillablePointer::new(closure);
183        let child_param = param.create_child();
184
185        extern "C" fn trampoline<F, T>(
186            param: *mut std::ffi::c_void,
187            read_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
188        ) where
189            T: Send + 'static,
190            F: FnOnce(&ReadSection) -> T,
191        {
192            unsafe {
193                let (child_param, result_ptr) = &mut *(param as *mut CallbackParam<F, T>);
194                let callback = child_param.as_mut().take().expect("Callback already taken");
195                let read_section = ReadSection::from_raw(read_section);
196                let res = callback(&read_section);
197                result_ptr.replace(res);
198            }
199        }
200
201        let trampoline_static = trampoline::<F, T>
202            as extern "C" fn(*mut std::ffi::c_void, *mut aviutl2_sys::plugin2::EDIT_SECTION);
203
204        let mut result = None;
205        let param = Box::<CallbackParam<F, T>>::new((child_param, &mut result));
206        let param_ptr = Box::into_raw(param);
207
208        let success = unsafe {
209            ((*self.internal).call_read_section_param)(
210                param_ptr as *mut std::ffi::c_void,
211                trampoline_static,
212            )
213        };
214
215        drop(unsafe { Box::from_raw(param_ptr) });
216
217        if success {
218            Ok(result.expect("Callback did not set result"))
219        } else {
220            Err(EditHandleError::ApiCallFailed)
221        }
222    }
223
224    /// 編集情報を取得する。
225    pub fn get_edit_info(&self) -> crate::generic::EditInfo {
226        assert!(
227            self.is_ready(),
228            "get_edit_info cannot be called before register_plugin is done"
229        );
230        let mut raw_info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::EDIT_INFO>::uninit();
231        unsafe {
232            ((*self.internal).get_edit_info)(
233                raw_info.as_mut_ptr(),
234                std::mem::size_of::<aviutl2_sys::plugin2::EDIT_INFO>() as _,
235            );
236            let edit_info = raw_info.assume_init();
237            crate::generic::EditInfo::from_raw(&edit_info)
238        }
239    }
240
241    /// ホストアプリケーションを再起動する。
242    pub fn restart_host_app(&self) {
243        assert!(
244            self.is_ready(),
245            "restart_host_app cannot be called before register_plugin is done"
246        );
247        unsafe {
248            ((*self.internal).restart_host_app)();
249        }
250    }
251
252    /// エフェクトの一覧をコールバック関数で取得する。
253    ///
254    /// # Note
255    ///
256    /// 不明なエフェクト種別があった場合はスキップされます。
257    pub fn enumerate_effects<F>(&self, callback: F)
258    where
259        F: FnMut(Effect),
260    {
261        assert!(
262            self.is_ready(),
263            "enumerate_effects cannot be called before register_plugin is done"
264        );
265        type CallbackParam<F> = ChildKillablePointer<F>;
266
267        extern "C" fn trampoline<F>(
268            param: *mut std::ffi::c_void,
269            name: aviutl2_sys::common::LPCWSTR,
270            r#type: i32,
271            flag: i32,
272        ) where
273            F: FnMut(Effect),
274        {
275            let callback = unsafe { &mut *(param as *mut CallbackParam<F>) };
276            let callback = unsafe { callback.as_mut() };
277            let name_str = unsafe { crate::common::load_wide_string(name) };
278            if let Ok(effect_type) = EffectType::try_from(r#type) {
279                let effect = Effect {
280                    name: name_str,
281                    effect_type,
282                    flag: EffectFlag::from_bits(flag),
283                };
284                callback(effect);
285            } else {
286                #[cfg(debug_assertions)]
287                tracing::warn!("Unknown effect type: {}", r#type);
288            }
289        }
290
291        let trampoline_static = trampoline::<F>
292            as extern "C" fn(*mut std::ffi::c_void, aviutl2_sys::common::LPCWSTR, i32, i32);
293        let callback_guard = KillablePointer::new(callback);
294        let child_param = callback_guard.create_child();
295        let param = Box::new(child_param);
296        let param_ptr = Box::into_raw(param);
297        unsafe {
298            ((*self.internal).enum_effect_name)(
299                param_ptr as *mut std::ffi::c_void,
300                trampoline_static,
301            );
302        }
303        drop(unsafe { Box::from_raw(param_ptr) });
304    }
305
306    /// エフェクトの一覧を取得する。
307    pub fn get_effects(&self) -> Vec<Effect> {
308        assert!(
309            self.is_ready(),
310            "get_effects cannot be called before register_plugin is done"
311        );
312        let mut effects = Vec::new();
313        self.enumerate_effects(|effect| {
314            effects.push(effect);
315        });
316        effects
317    }
318
319    /// エフェクトの設定項目一覧をコールバック関数で取得する。
320    ///
321    /// # Arguments
322    ///
323    /// - `effect`: 対象のエフェクト名。エイリアスファイルの `effect.name` を指定します。
324    ///
325    /// # Note
326    ///
327    /// 不明な設定項目種別があった場合はスキップされます。
328    pub fn enumerate_effect_items<F>(
329        &self,
330        effect: &str,
331        callback: F,
332    ) -> Result<(), EditHandleError>
333    where
334        F: FnMut(EffectItemInfo),
335    {
336        assert!(
337            self.is_ready(),
338            "enumerate_effect_items cannot be called before register_plugin is done"
339        );
340        type CallbackParam<F> = ChildKillablePointer<F>;
341
342        unsafe extern "C" fn trampoline<F>(
343            param: *mut std::ffi::c_void,
344            name: aviutl2_sys::common::LPCWSTR,
345            r#type: i32,
346        ) where
347            F: FnMut(EffectItemInfo),
348        {
349            let callback = unsafe { &mut *(param as *mut CallbackParam<F>) };
350            let callback = unsafe { callback.as_mut() };
351            let name = unsafe { crate::common::load_wide_string(name) };
352            if let Some(info) = effect_item_info_from_raw(name, r#type) {
353                callback(info);
354            }
355        }
356
357        let effect = crate::common::CWString::new(effect)?;
358        let trampoline_static = trampoline::<F>
359            as unsafe extern "C" fn(*mut std::ffi::c_void, aviutl2_sys::common::LPCWSTR, i32);
360        let callback_guard = KillablePointer::new(callback);
361        let child_param = callback_guard.create_child();
362        let param = Box::new(child_param);
363        let param_ptr = Box::into_raw(param);
364        let success = unsafe {
365            ((*self.internal).enum_effect_item)(
366                effect.as_ptr(),
367                param_ptr as *mut std::ffi::c_void,
368                trampoline_static,
369            )
370        };
371        drop(unsafe { Box::from_raw(param_ptr) });
372
373        if success {
374            Ok(())
375        } else {
376            Err(EditHandleError::EffectNotFound)
377        }
378    }
379
380    /// エフェクトの設定項目一覧を取得する。
381    ///
382    /// # Arguments
383    ///
384    /// - `effect`: 対象のエフェクト名。エイリアスファイルの `effect.name` を指定します。
385    pub fn get_effect_items(&self, effect: &str) -> Result<Vec<EffectItemInfo>, EditHandleError> {
386        assert!(
387            self.is_ready(),
388            "get_effect_items cannot be called before register_plugin is done"
389        );
390        let mut items = Vec::new();
391        self.enumerate_effect_items(effect, |item| {
392            items.push(item);
393        })?;
394        Ok(items)
395    }
396
397    /// 指定の設定項目が所属するグループ内での所属インデックスを取得する。
398    pub fn get_effect_item_group_index(
399        &self,
400        effect: &str,
401        item_name: &str,
402    ) -> Result<Option<usize>, EditHandleError> {
403        assert!(
404            self.is_ready(),
405            "get_effect_item_group_index cannot be called before register_plugin is done"
406        );
407        let effect = crate::common::CWString::new(effect)?;
408        let item_name = crate::common::CWString::new(item_name)?;
409        let item_count = unsafe {
410            ((*self.internal).get_effect_item_group_names)(
411                effect.as_ptr(),
412                item_name.as_ptr(),
413                std::ptr::null_mut(),
414                0,
415                std::ptr::null_mut(),
416            )
417        };
418        if item_count <= 0 {
419            return Ok(None);
420        }
421
422        let mut names: Vec<*const u16> = vec![std::ptr::null(); item_count as usize];
423        let mut index: i32 = -1;
424        unsafe {
425            ((*self.internal).get_effect_item_group_names)(
426                effect.as_ptr(),
427                item_name.as_ptr(),
428                names.as_mut_ptr(),
429                item_count,
430                &mut index as *mut i32,
431            )
432        };
433        if index < 0 {
434            return Err(EditHandleError::ApiCallFailed);
435        }
436        Ok(Some(index as usize))
437    }
438
439    /// 指定の設定項目が所属するグループ、または指定したグループの所属アイテム名を取得する。
440    pub fn get_effect_item_group_names(
441        &self,
442        effect: &str,
443        item_name: &str,
444    ) -> Result<Option<Vec<String>>, EditHandleError> {
445        assert!(
446            self.is_ready(),
447            "get_effect_item_group_names cannot be called before register_plugin is done"
448        );
449        let effect = crate::common::CWString::new(effect)?;
450        let item_name = crate::common::CWString::new(item_name)?;
451        let item_count = unsafe {
452            ((*self.internal).get_effect_item_group_names)(
453                effect.as_ptr(),
454                item_name.as_ptr(),
455                std::ptr::null_mut(),
456                0,
457                std::ptr::null_mut(),
458            )
459        };
460        if item_count <= 0 {
461            return Ok(None);
462        }
463
464        let mut names: Vec<*const u16> = vec![std::ptr::null(); item_count as usize];
465        let actual_item_count = unsafe {
466            ((*self.internal).get_effect_item_group_names)(
467                effect.as_ptr(),
468                item_name.as_ptr(),
469                names.as_mut_ptr(),
470                item_count,
471                std::ptr::null_mut(),
472            )
473        };
474
475        if actual_item_count != item_count {
476            return Err(EditHandleError::ApiCallFailed);
477        }
478
479        let names: Vec<String> = names
480            .into_iter()
481            .map(|ptr| unsafe { crate::common::load_wide_string(ptr) })
482            .collect();
483
484        Ok(Some(names))
485    }
486
487    /// モジュールの一覧をコールバック関数で取得する。
488    pub fn enumerate_modules<F>(&self, callback: F)
489    where
490        F: FnMut(ModuleInfo),
491    {
492        assert!(
493            self.is_ready(),
494            "enumerate_modules cannot be called before register_plugin is done"
495        );
496        type CallbackParam<F> = ChildKillablePointer<F>;
497
498        extern "C" fn trampoline<F>(
499            param: *mut std::ffi::c_void,
500            module: *mut aviutl2_sys::plugin2::MODULE_INFO,
501        ) where
502            F: FnMut(ModuleInfo),
503        {
504            let callback = unsafe { &mut *(param as *mut CallbackParam<F>) };
505            let callback = unsafe { callback.as_mut() };
506            if let Some(module_info) = module_info_from_raw(module) {
507                callback(module_info);
508            }
509        }
510        let trampoline_static = trampoline::<F>
511            as unsafe extern "C" fn(*mut std::ffi::c_void, *mut aviutl2_sys::plugin2::MODULE_INFO);
512        let callback_guard = KillablePointer::new(callback);
513        let child_param = callback_guard.create_child();
514        let param = Box::new(child_param);
515        let param_ptr = Box::into_raw(param);
516        unsafe {
517            ((*self.internal).enum_module_info)(
518                param_ptr as *mut std::ffi::c_void,
519                trampoline_static,
520            );
521        }
522        drop(unsafe { Box::from_raw(param_ptr) });
523    }
524
525    /// モジュールの一覧を取得する。
526    pub fn get_modules(&self) -> Vec<ModuleInfo> {
527        assert!(
528            self.is_ready(),
529            "get_modules cannot be called before register_plugin is done"
530        );
531        let mut modules = Vec::new();
532        self.enumerate_modules(|module| {
533            modules.push(module);
534        });
535        modules
536    }
537
538    /// ホストアプリケーションのメインウィンドウのハンドルを[`raw_window_handle::Win32WindowHandle`]として取得する。
539    pub fn get_host_app_window_raw(&self) -> Option<raw_window_handle::Win32WindowHandle> {
540        let hwnd = unsafe { ((*self.internal).get_host_app_window)() };
541        NonZeroIsize::new(hwnd as isize).map(raw_window_handle::Win32WindowHandle::new)
542    }
543
544    /// ホストアプリケーションのメインウィンドウのハンドルを[`raw_window_handle::WindowHandle`]として取得する。
545    ///
546    /// # Safety
547    ///
548    /// [`raw_window_handle::WindowHandle::borrow_raw`] を参照してください。
549    pub unsafe fn get_host_app_window(&'_ self) -> Option<raw_window_handle::WindowHandle<'_>> {
550        self.get_host_app_window_raw().map(|handle| unsafe {
551            raw_window_handle::WindowHandle::borrow_raw(raw_window_handle::RawWindowHandle::Win32(
552                handle,
553            ))
554        })
555    }
556
557    /// 編集状態を取得する。
558    pub fn get_edit_state(&self) -> Result<EditState, EditHandleError> {
559        assert!(
560            self.is_ready(),
561            "get_edit_state cannot be called before register_plugin is done"
562        );
563        let state = unsafe { ((*self.internal).get_edit_state)() };
564        EditState::try_from(state).map_err(|_| EditHandleError::UnknownEditState(state))
565    }
566
567    /// 現在のシーンの映像レンダリングを要求する。
568    ///
569    /// この関数はレンダリングタスクの追加のみを行います。レンダリング完了時に
570    /// コールバックがイベント通知スレッドから呼ばれます。
571    pub fn rendering_scene_video<F>(&self, frame: u32, callback: F) -> Result<(), EditHandleError>
572    where
573        F: FnMut(RenderingSceneVideo<'_>) + Send + 'static,
574    {
575        assert!(
576            self.is_ready(),
577            "rendering_scene_video cannot be called before register_plugin is done"
578        );
579
580        type CallbackParam<F> = Mutex<Option<F>>;
581
582        unsafe extern "C" fn trampoline<F>(
583            param: *mut std::ffi::c_void,
584            frame: i32,
585            buffer: *const std::ffi::c_void,
586            width: i32,
587            height: i32,
588            pitch: i32,
589        ) where
590            F: FnMut(RenderingSceneVideo<'_>),
591        {
592            let callback = unsafe { Box::from_raw(param as *mut CallbackParam<F>) };
593            let len = usize::try_from(pitch)
594                .ok()
595                .and_then(|pitch| {
596                    usize::try_from(height)
597                        .ok()
598                        .and_then(|height| pitch.checked_mul(height))
599                })
600                .unwrap_or(0);
601            let buffer = if buffer.is_null() || len == 0 {
602                &[]
603            } else {
604                unsafe { std::slice::from_raw_parts(buffer as *const u8, len) }
605            };
606            let video = RenderingSceneVideo {
607                frame: frame as u32,
608                width: width as u32,
609                height: height as u32,
610                pitch: pitch as u32,
611                buffer,
612            };
613            let mut callback = callback
614                .lock()
615                .unwrap()
616                .take()
617                .expect("Callback already taken");
618            callback(video);
619        }
620
621        let frame = i32::try_from(frame).map_err(|_| EditHandleError::ValueOutOfRange)?;
622        let param = Box::into_raw(Box::new(Mutex::new(Some(callback))));
623        let success = unsafe {
624            ((*self.internal).rendering_scene_video)(
625                frame,
626                param as *mut std::ffi::c_void,
627                trampoline::<F>,
628            )
629        };
630        if success {
631            Ok(())
632        } else {
633            unsafe {
634                drop(Box::from_raw(param));
635            }
636            Err(EditHandleError::ApiCallFailed)
637        }
638    }
639
640    /// 現在のシーンの音声レンダリングを要求する。
641    ///
642    /// この関数はレンダリングタスクの追加のみを行います。レンダリング完了時に
643    /// コールバックがイベント通知スレッドから呼ばれます。
644    pub fn rendering_scene_audio<F>(&self, frame: u32, callback: F) -> Result<(), EditHandleError>
645    where
646        F: FnMut(RenderingSceneAudio<'_>) + Send + 'static,
647    {
648        assert!(
649            self.is_ready(),
650            "rendering_scene_audio cannot be called before register_plugin is done"
651        );
652
653        type CallbackParam<F> = Mutex<Option<F>>;
654
655        unsafe extern "C" fn trampoline<F>(
656            param: *mut std::ffi::c_void,
657            frame: i32,
658            buffer0: *const f32,
659            buffer1: *const f32,
660            sample_num: i32,
661        ) where
662            F: FnMut(RenderingSceneAudio<'_>),
663        {
664            let callback = unsafe { Box::from_raw(param as *mut CallbackParam<F>) };
665            let len = usize::try_from(sample_num).unwrap_or(0);
666            let buffer0 = if buffer0.is_null() || len == 0 {
667                &[]
668            } else {
669                unsafe { std::slice::from_raw_parts(buffer0, len) }
670            };
671            let buffer1 = if buffer1.is_null() || len == 0 {
672                &[]
673            } else {
674                unsafe { std::slice::from_raw_parts(buffer1, len) }
675            };
676            let audio = RenderingSceneAudio {
677                frame: frame as u32,
678                buffer0,
679                buffer1,
680            };
681            let mut callback = callback
682                .lock()
683                .unwrap()
684                .take()
685                .expect("Callback already taken");
686            callback(audio);
687        }
688
689        let frame = i32::try_from(frame).map_err(|_| EditHandleError::ValueOutOfRange)?;
690        let param = Box::into_raw(Box::new(Mutex::new(Some(callback))));
691        let success = unsafe {
692            ((*self.internal).rendering_scene_audio)(
693                frame,
694                param as *mut std::ffi::c_void,
695                trampoline::<F>,
696            )
697        };
698        if success {
699            Ok(())
700        } else {
701            unsafe {
702                drop(Box::from_raw(param));
703            }
704            Err(EditHandleError::ApiCallFailed)
705        }
706    }
707
708    /// 指定のオブジェクトの映像のレンダリングを要求する。
709    ///
710    /// レンダリング完了時はイベント通知スレッドからコールバックが呼ばれます。
711    ///
712    /// # Arguments
713    ///
714    /// - `object`:レンダリング対象のオブジェクト。
715    /// - `frame`:レンダリング対象のフレーム番号。
716    /// - `apply_effect`:レンダリング時にエフェクトを適用するかどうか。
717    /// - `callback`:レンダリング完了時に呼ばれるコールバック関数。
718    pub fn rendering_object_video<F>(
719        &self,
720        object: crate::generic::ObjectHandle,
721        frame: u32,
722        apply_effect: bool,
723        callback: F,
724    ) -> Result<(), EditHandleError>
725    where
726        F: FnMut(RenderingSceneVideo<'_>) + Send + 'static,
727    {
728        assert!(
729            self.is_ready(),
730            "rendering_object_video cannot be called before register_plugin is done"
731        );
732
733        type CallbackParam<F> = Mutex<Option<F>>;
734
735        unsafe extern "C" fn trampoline<F>(
736            param: *mut std::ffi::c_void,
737            frame: i32,
738            buffer: *const std::ffi::c_void,
739            width: i32,
740            height: i32,
741            pitch: i32,
742        ) where
743            F: FnMut(RenderingSceneVideo<'_>),
744        {
745            let callback = unsafe { Box::from_raw(param as *mut CallbackParam<F>) };
746            let len = usize::try_from(pitch)
747                .ok()
748                .and_then(|pitch| {
749                    usize::try_from(height)
750                        .ok()
751                        .and_then(|height| pitch.checked_mul(height))
752                })
753                .unwrap_or(0);
754            let buffer = if buffer.is_null() || len == 0 {
755                &[]
756            } else {
757                unsafe { std::slice::from_raw_parts(buffer as *const u8, len) }
758            };
759            let video = RenderingSceneVideo {
760                frame: frame as u32,
761                width: width as u32,
762                height: height as u32,
763                pitch: pitch as u32,
764                buffer,
765            };
766            let mut callback = callback
767                .lock()
768                .unwrap()
769                .take()
770                .expect("Callback already taken");
771            callback(video);
772        }
773
774        let frame = i32::try_from(frame).map_err(|_| EditHandleError::ValueOutOfRange)?;
775        let param = Box::into_raw(Box::new(Mutex::new(Some(callback))));
776        let success = unsafe {
777            ((*self.internal).rendering_object_video)(
778                object.internal,
779                frame,
780                apply_effect as _,
781                param as *mut std::ffi::c_void,
782                trampoline::<F>,
783            )
784        };
785        if success {
786            Ok(())
787        } else {
788            unsafe {
789                drop(Box::from_raw(param));
790            }
791            Err(EditHandleError::ApiCallFailed)
792        }
793    }
794
795    /// 指定のオブジェクトの音声のレンダリングを要求する。
796    ///
797    /// レンダリング完了時はイベント通知スレッドからコールバックが呼ばれます。
798    ///
799    /// # Arguments
800    ///
801    /// - `object`:レンダリング対象のオブジェクト。
802    /// - `frame`:レンダリング対象のフレーム番号。
803    /// - `apply_effect`:レンダリング時にエフェクトを適用するかどうか。
804    /// - `callback`:レンダリング完了時に呼ばれるコールバック関数。
805    pub fn rendering_object_audio<F>(
806        &self,
807        object: crate::generic::ObjectHandle,
808        frame: u32,
809        apply_effect: bool,
810        callback: F,
811    ) -> Result<(), EditHandleError>
812    where
813        F: FnMut(RenderingSceneAudio<'_>) + Send + 'static,
814    {
815        assert!(
816            self.is_ready(),
817            "rendering_object_audio cannot be called before register_plugin is done"
818        );
819
820        type CallbackParam<F> = Mutex<Option<F>>;
821
822        unsafe extern "C" fn trampoline<F>(
823            param: *mut std::ffi::c_void,
824            frame: i32,
825            buffer0: *const f32,
826            buffer1: *const f32,
827            sample_num: i32,
828        ) where
829            F: FnMut(RenderingSceneAudio<'_>),
830        {
831            let callback = unsafe { Box::from_raw(param as *mut CallbackParam<F>) };
832            let len = usize::try_from(sample_num).unwrap_or(0);
833            let buffer0 = if buffer0.is_null() || len == 0 {
834                &[]
835            } else {
836                unsafe { std::slice::from_raw_parts(buffer0, len) }
837            };
838            let buffer1 = if buffer1.is_null() || len == 0 {
839                &[]
840            } else {
841                unsafe { std::slice::from_raw_parts(buffer1, len) }
842            };
843            let audio = RenderingSceneAudio {
844                frame: frame as u32,
845                buffer0,
846                buffer1,
847            };
848            let mut callback = callback
849                .lock()
850                .unwrap()
851                .take()
852                .expect("Callback already taken");
853            callback(audio);
854        }
855
856        let frame = i32::try_from(frame).map_err(|_| EditHandleError::ValueOutOfRange)?;
857        let param = Box::into_raw(Box::new(Mutex::new(Some(callback))));
858        let success = unsafe {
859            ((*self.internal).rendering_object_audio)(
860                object.internal,
861                frame,
862                apply_effect as _,
863                param as *mut std::ffi::c_void,
864                trampoline::<F>,
865            )
866        };
867        if success {
868            Ok(())
869        } else {
870            unsafe {
871                drop(Box::from_raw(param));
872            }
873            Err(EditHandleError::ApiCallFailed)
874        }
875    }
876
877    /// レンダリング中のタスクが全て完了するまで待機する。
878    ///
879    /// # Note
880    ///
881    /// <div class="warning">
882    ///
883    /// この関数を[`Self::call_read_section`]や[`Self::call_edit_section`]のコールバック内で呼び出すとデッドロックする可能性があります。
884    ///
885    /// </div>
886    pub fn wait_rendering_task(&self) {
887        assert!(
888            self.is_ready(),
889            "wait_rendering_task cannot be called before register_plugin is done"
890        );
891        unsafe {
892            ((*self.internal).wait_rendering_task)();
893        }
894    }
895
896    /// フォント名の一覧をコールバック関数で取得する。
897    pub fn enumerate_font_names<F>(&self, callback: F)
898    where
899        F: FnMut(String),
900    {
901        assert!(
902            self.is_ready(),
903            "enumerate_font_names cannot be called before register_plugin is done"
904        );
905        type CallbackParam<F> = ChildKillablePointer<F>;
906
907        unsafe extern "C" fn trampoline<F>(
908            param: *mut std::ffi::c_void,
909            name: aviutl2_sys::common::LPCWSTR,
910        ) where
911            F: FnMut(String),
912        {
913            let callback = unsafe { &mut *(param as *mut CallbackParam<F>) };
914            let callback = unsafe { callback.as_mut() };
915            let name_str = unsafe { crate::common::load_wide_string(name) };
916            callback(name_str);
917        }
918
919        let trampoline_static = trampoline::<F>
920            as unsafe extern "C" fn(*mut std::ffi::c_void, aviutl2_sys::common::LPCWSTR);
921        let callback_guard = KillablePointer::new(callback);
922        let child_param = callback_guard.create_child();
923        let param = Box::new(child_param);
924        let param_ptr = Box::into_raw(param);
925        unsafe {
926            ((*self.internal).enum_font_name)(
927                param_ptr as *mut std::ffi::c_void,
928                trampoline_static,
929            );
930        }
931        drop(unsafe { Box::from_raw(param_ptr) });
932    }
933
934    /// フォント名の一覧を取得する。
935    pub fn get_font_names(&self) -> Vec<String> {
936        assert!(
937            self.is_ready(),
938            "get_font_names cannot be called before register_plugin is done"
939        );
940        let mut font_names = Vec::new();
941        self.enumerate_font_names(|name| {
942            font_names.push(name);
943        });
944        font_names
945    }
946
947    /// パレット名の一覧をコールバック関数で取得する。
948    pub fn enumerate_palette_names<F>(&self, callback: F)
949    where
950        F: FnMut(String),
951    {
952        assert!(
953            self.is_ready(),
954            "enumerate_palette_names cannot be called before register_plugin is done"
955        );
956        type CallbackParam<F> = ChildKillablePointer<F>;
957
958        unsafe extern "C" fn trampoline<F>(
959            param: *mut std::ffi::c_void,
960            name: aviutl2_sys::common::LPCWSTR,
961        ) where
962            F: FnMut(String),
963        {
964            let callback = unsafe { &mut *(param as *mut CallbackParam<F>) };
965            let callback = unsafe { callback.as_mut() };
966            let name_str = unsafe { crate::common::load_wide_string(name) };
967            callback(name_str);
968        }
969
970        let trampoline_static = trampoline::<F>
971            as unsafe extern "C" fn(*mut std::ffi::c_void, aviutl2_sys::common::LPCWSTR);
972        let callback_guard = KillablePointer::new(callback);
973        let child_param = callback_guard.create_child();
974        let param = Box::new(child_param);
975        let param_ptr = Box::into_raw(param);
976        unsafe {
977            ((*self.internal).enum_palette_name)(
978                param_ptr as *mut std::ffi::c_void,
979                trampoline_static,
980            );
981        }
982        drop(unsafe { Box::from_raw(param_ptr) });
983    }
984
985    /// パレット名の一覧を取得する。
986    pub fn get_palette_names(&self) -> Vec<String> {
987        assert!(
988            self.is_ready(),
989            "get_palette_names cannot be called before register_plugin is done"
990        );
991        let mut palette_names = Vec::new();
992        self.enumerate_palette_names(|name| {
993            palette_names.push(name);
994        });
995        palette_names
996    }
997}
998
999/// エフェクト情報。
1000#[derive(Debug, Clone, PartialEq, Eq)]
1001pub struct Effect {
1002    /// エフェクト名。
1003    pub name: String,
1004    /// エフェクト種別。
1005    pub effect_type: EffectType,
1006    /// フラグ。
1007    pub flag: EffectFlag,
1008}
1009
1010/// エフェクトの設定項目情報。
1011#[derive(Debug, Clone, PartialEq, Eq)]
1012pub struct EffectItemInfo {
1013    /// 設定項目名。
1014    pub name: String,
1015    /// 設定項目種別。
1016    pub item_type: EffectItemType,
1017}
1018
1019/// エフェクト種別。
1020#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1021pub enum EffectType {
1022    /// フィルタ効果。
1023    Filter,
1024    /// メディア入力。
1025    Input,
1026    /// シーンチェンジ。
1027    SceneChange,
1028    /// オブジェクト制御。
1029    Control,
1030    /// メディア出力。
1031    Output,
1032}
1033
1034/// 設定項目種別。
1035#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1036pub enum EffectItemType {
1037    /// 整数。
1038    Integer,
1039    /// 数値(トラックバー)。
1040    Number,
1041    /// チェックボックス。
1042    Check,
1043    /// テキスト。
1044    Text,
1045    /// 文字列。
1046    String,
1047    /// ファイル。
1048    File,
1049    /// 色。
1050    Color,
1051    /// リスト選択。
1052    Select,
1053    /// シーン。
1054    Scene,
1055    /// レイヤー範囲。
1056    Range,
1057    /// リストと文字の複合。
1058    Combo,
1059    /// マスク。
1060    Mask,
1061    /// フォント。
1062    Font,
1063    /// 図形。
1064    Figure,
1065    /// データ。
1066    Data,
1067    /// フォルダ。
1068    Folder,
1069    /// 数値(トラックバー)グループ。
1070    NumberGroup,
1071    /// 設定グループ。(明示的なグループのみ)
1072    Group,
1073    /// セパレーター。
1074    Separator,
1075}
1076
1077define_bitflag! {
1078    /// エフェクトのフラグ。
1079    #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
1080    #[non_exhaustive]
1081    pub struct EffectFlag: i32 {
1082        /// 画像フィルタをサポートするかどうか。
1083        video: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_VIDEO,
1084
1085        /// 音声フィルタをサポートするかどうか。
1086        audio: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_AUDIO,
1087
1088        /// フィルタオブジェクトをサポートするかどうか。
1089        as_filter: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_FILTER,
1090
1091        /// カメラ効果をサポートするかどうか。
1092        camera: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_CAMERA,
1093    }
1094}
1095
1096impl TryFrom<i32> for EffectType {
1097    type Error = ();
1098
1099    fn try_from(value: i32) -> Result<Self, Self::Error> {
1100        match value {
1101            1 => Ok(EffectType::Filter),
1102            2 => Ok(EffectType::Input),
1103            3 => Ok(EffectType::SceneChange),
1104            4 => Ok(EffectType::Control),
1105            5 => Ok(EffectType::Output),
1106            _ => Err(()),
1107        }
1108    }
1109}
1110impl From<EffectType> for i32 {
1111    fn from(value: EffectType) -> Self {
1112        match value {
1113            EffectType::Filter => 1,
1114            EffectType::Input => 2,
1115            EffectType::SceneChange => 3,
1116            EffectType::Control => 4,
1117            EffectType::Output => 5,
1118        }
1119    }
1120}
1121
1122impl TryFrom<i32> for EffectItemType {
1123    type Error = ();
1124
1125    fn try_from(value: i32) -> Result<Self, Self::Error> {
1126        match value {
1127            1 => Ok(EffectItemType::Integer),
1128            2 => Ok(EffectItemType::Number),
1129            3 => Ok(EffectItemType::Check),
1130            4 => Ok(EffectItemType::Text),
1131            5 => Ok(EffectItemType::String),
1132            6 => Ok(EffectItemType::File),
1133            7 => Ok(EffectItemType::Color),
1134            8 => Ok(EffectItemType::Select),
1135            9 => Ok(EffectItemType::Scene),
1136            10 => Ok(EffectItemType::Range),
1137            11 => Ok(EffectItemType::Combo),
1138            12 => Ok(EffectItemType::Mask),
1139            13 => Ok(EffectItemType::Font),
1140            14 => Ok(EffectItemType::Figure),
1141            15 => Ok(EffectItemType::Data),
1142            16 => Ok(EffectItemType::Folder),
1143            17 => Ok(EffectItemType::NumberGroup),
1144            18 => Ok(EffectItemType::Group),
1145            19 => Ok(EffectItemType::Separator),
1146            _ => Err(()),
1147        }
1148    }
1149}
1150impl From<EffectItemType> for i32 {
1151    fn from(value: EffectItemType) -> Self {
1152        match value {
1153            EffectItemType::Integer => 1,
1154            EffectItemType::Number => 2,
1155            EffectItemType::Check => 3,
1156            EffectItemType::Text => 4,
1157            EffectItemType::String => 5,
1158            EffectItemType::File => 6,
1159            EffectItemType::Color => 7,
1160            EffectItemType::Select => 8,
1161            EffectItemType::Scene => 9,
1162            EffectItemType::Range => 10,
1163            EffectItemType::Combo => 11,
1164            EffectItemType::Mask => 12,
1165            EffectItemType::Font => 13,
1166            EffectItemType::Figure => 14,
1167            EffectItemType::Data => 15,
1168            EffectItemType::Folder => 16,
1169            EffectItemType::NumberGroup => 17,
1170            EffectItemType::Group => 18,
1171            EffectItemType::Separator => 19,
1172        }
1173    }
1174}
1175
1176/// モジュール情報。
1177#[derive(Debug, Clone, PartialEq, Eq)]
1178pub struct ModuleInfo {
1179    /// モジュール種別。
1180    pub module_type: ModuleType,
1181    /// 名前。
1182    pub name: String,
1183    /// 情報。
1184    pub information: String,
1185}
1186
1187/// モジュール種別。
1188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1189pub enum ModuleType {
1190    /// フィルタスクリプト。
1191    ScriptFilter,
1192    /// オブジェクトスクリプト。
1193    ScriptObject,
1194    /// カメラスクリプト。
1195    ScriptCamera,
1196    /// トラックバースクリプト。
1197    ScriptTrack,
1198    /// スクリプトモジュール。
1199    ScriptModule,
1200    /// 入力プラグイン。
1201    PluginInput,
1202    /// 出力プラグイン。
1203    PluginOutput,
1204    /// フィルタプラグイン。
1205    PluginFilter,
1206    /// 汎用プラグイン。
1207    PluginGeneric,
1208}
1209
1210impl TryFrom<i32> for ModuleType {
1211    type Error = ();
1212
1213    fn try_from(value: i32) -> Result<Self, Self::Error> {
1214        match value {
1215            1 => Ok(ModuleType::ScriptFilter),
1216            2 => Ok(ModuleType::ScriptObject),
1217            3 => Ok(ModuleType::ScriptCamera),
1218            4 => Ok(ModuleType::ScriptTrack),
1219            5 => Ok(ModuleType::ScriptModule),
1220            6 => Ok(ModuleType::PluginInput),
1221            7 => Ok(ModuleType::PluginOutput),
1222            8 => Ok(ModuleType::PluginFilter),
1223            9 => Ok(ModuleType::PluginGeneric),
1224            _ => Err(()),
1225        }
1226    }
1227}
1228impl From<ModuleType> for i32 {
1229    fn from(value: ModuleType) -> Self {
1230        match value {
1231            ModuleType::ScriptFilter => 1,
1232            ModuleType::ScriptObject => 2,
1233            ModuleType::ScriptCamera => 3,
1234            ModuleType::ScriptTrack => 4,
1235            ModuleType::ScriptModule => 5,
1236            ModuleType::PluginInput => 6,
1237            ModuleType::PluginOutput => 7,
1238            ModuleType::PluginFilter => 8,
1239            ModuleType::PluginGeneric => 9,
1240        }
1241    }
1242}
1243
1244/// 編集状態。
1245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1246pub enum EditState {
1247    /// 編集中
1248    Edit,
1249    /// プレビュー再生中
1250    Preview,
1251    /// ファイル出力中
1252    Save,
1253}
1254
1255impl TryFrom<i32> for EditState {
1256    type Error = ();
1257
1258    fn try_from(value: i32) -> Result<Self, Self::Error> {
1259        match value {
1260            0 => Ok(EditState::Edit),
1261            1 => Ok(EditState::Preview),
1262            2 => Ok(EditState::Save),
1263            _ => Err(()),
1264        }
1265    }
1266}
1267impl From<EditState> for i32 {
1268    fn from(value: EditState) -> Self {
1269        match value {
1270            EditState::Edit => 0,
1271            EditState::Preview => 1,
1272            EditState::Save => 2,
1273        }
1274    }
1275}
1276
1277/// グローバルに [EditHandle] を保持するための構造体。
1278///
1279/// `OnceLock` と違い、もし初期化していない状態でアクセスした場合にパニックします。
1280#[derive(Debug)]
1281pub struct GlobalEditHandle {
1282    edit_handle: std::sync::OnceLock<crate::generic::EditHandle>,
1283}
1284
1285impl GlobalEditHandle {
1286    /// 新しいインスタンスを作成する。
1287    pub const fn new() -> Self {
1288        Self {
1289            edit_handle: std::sync::OnceLock::new(),
1290        }
1291    }
1292
1293    /// 初期化する。すでに初期化されている場合は警告をログに出力します。
1294    pub fn init(&self, edit_handle: crate::generic::EditHandle) {
1295        let _ = self
1296            .edit_handle
1297            .set(edit_handle)
1298            .map_err(|_| tracing::warn!("GlobalEditHandle was already initialized"));
1299    }
1300
1301    /// 初期化されているかどうかを確認します。
1302    pub fn is_ready(&self) -> bool {
1303        self.edit_handle
1304            .get()
1305            .is_some_and(|handle| handle.is_ready())
1306    }
1307}
1308
1309impl Default for GlobalEditHandle {
1310    fn default() -> Self {
1311        Self::new()
1312    }
1313}
1314
1315impl std::ops::Deref for GlobalEditHandle {
1316    type Target = crate::generic::EditHandle;
1317
1318    fn deref(&self) -> &Self::Target {
1319        self.edit_handle
1320            .get()
1321            .expect("GlobalEditHandle is not initialized")
1322    }
1323}
1324
1325fn effect_item_info_from_raw(name: String, item_type: i32) -> Option<EffectItemInfo> {
1326    if let Ok(item_type) = EffectItemType::try_from(item_type) {
1327        Some(EffectItemInfo { name, item_type })
1328    } else {
1329        tracing::warn!("Unknown effect item type: {}", item_type);
1330        None
1331    }
1332}
1333
1334fn module_info_from_raw(raw: *mut aviutl2_sys::plugin2::MODULE_INFO) -> Option<ModuleInfo> {
1335    let module_type = unsafe { (*raw).r#type };
1336    if let Ok(module_type) = ModuleType::try_from(module_type) {
1337        Some(ModuleInfo {
1338            module_type,
1339            name: unsafe { crate::common::load_wide_string((*raw).name) },
1340            information: unsafe { crate::common::load_wide_string((*raw).information) },
1341        })
1342    } else {
1343        tracing::warn!("Unknown module type: {}", module_type);
1344        None
1345    }
1346}
1347
1348#[cfg(test)]
1349mod tests {
1350    use super::*;
1351
1352    #[test]
1353    fn effect_item_type_try_from_known_values() {
1354        assert_eq!(EffectItemType::try_from(1), Ok(EffectItemType::Integer));
1355        assert_eq!(EffectItemType::try_from(8), Ok(EffectItemType::Select));
1356        assert_eq!(EffectItemType::try_from(16), Ok(EffectItemType::Folder));
1357    }
1358
1359    #[test]
1360    fn effect_item_type_try_from_unknown_value_fails() {
1361        assert_eq!(EffectItemType::try_from(999), Err(()));
1362    }
1363
1364    #[test]
1365    fn effect_item_type_into_i32() {
1366        assert_eq!(i32::from(EffectItemType::Integer), 1);
1367        assert_eq!(i32::from(EffectItemType::Combo), 11);
1368        assert_eq!(i32::from(EffectItemType::Folder), 16);
1369    }
1370
1371    #[test]
1372    fn effect_item_info_from_raw_returns_none_for_unknown_type() {
1373        assert_eq!(effect_item_info_from_raw("test".to_string(), 999), None);
1374    }
1375
1376    #[test]
1377    fn effect_item_info_from_raw_builds_info_for_known_type() {
1378        assert_eq!(
1379            effect_item_info_from_raw("test".to_string(), 4),
1380            Some(EffectItemInfo {
1381                name: "test".to_string(),
1382                item_type: EffectItemType::Text,
1383            })
1384        );
1385    }
1386
1387    #[test]
1388    fn module_type_try_from_unknown_value_fails() {
1389        assert_eq!(ModuleType::try_from(999), Err(()));
1390    }
1391
1392    #[test]
1393    fn edit_state_try_from_unknown_value_fails() {
1394        assert_eq!(EditState::try_from(999), Err(()));
1395    }
1396}